package de.nordakademie.wpk.share.core.data.webdata;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;

import de.nordakademie.wpk.share.core.data.webdata.webservicex.StockQuote;
import de.nordakademie.wpk.share.core.data.webdata.webservicex.StockQuoteObj;
import de.nordakademie.wpk.share.core.data.webdata.webservicex.StockQuoteSoap;
import de.nordakademie.wpk.share.core.data.webdata.webservicex.StockQuoteObj.Stock;

/**
 * This class offers a method to get a stock update via webservice or from yahoo
 * finance for a specified symbol.
 * 
 * @author Bent Juergensen
 * 
 */
public class StockData {

	public StockData() {

	}
	
	/**
	 * Method returns a StockQuote object with the stocks needed from the webservice. 
	 * 
	 * @param ArrayList<String> symbols which name the needed stocks
	 * @return StockQuoteObject with Stocks
	 */
	public static StockQuoteObj getWebserviceData(ArrayList<String> symbols) {
		String symbolStr = generateSymbolString(symbols);
		StockQuote service = new StockQuote();
		StockQuoteSoap greeting = service.getStockQuoteSoap();
		String input = greeting.getQuote(symbolStr);
		JAXBContext jc = null;
		StockQuoteObj sb = null;
		try {
			jc = JAXBContext.newInstance(StockQuoteObj.class);
			javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
			sb = (StockQuoteObj) um.unmarshal(new StringReader(input));
		} catch (JAXBException e) {
			e.printStackTrace();
		}
		return sb;
	}
	
	private static String generateSymbolString(ArrayList<String> symbols){
		String symbolStr = "";
		boolean isFirst = true;
		for (String s : symbols) {
			if(isFirst)
				symbolStr += s;
			else
				symbolStr += "+ " + s;
			isFirst = false;
		}
		symbolStr += "'";
		return symbolStr;		
	}

	/**
	 * Method fetches a csv file from yahoo finance api and creates a Stock
	 * object with the data from the date mentioned till date -1 month.
	 * 
	 * @param symbol
	 *            String with symbol of needed share data
	 * @param day
	 *            int day in the month (1-31)
	 * @param month
	 *            int month, STARTING WITH 0 (January = 0)
	 * @param year
	 *            int year which shall be looked at
	 * 
	 * @return Stock object with stock data, Stock Object is null if no data
	 *         could get fetched.
	 */
	public static ArrayList<Stock> getHistoricYahooData(String symbol, int day,
			int month, int year) {
		int startDay = day;
		int startMonth = month;
		int startYear = year;
		int endDay = day;
		int endMonth = month;
		int endYear = year;
		String csvData;
		URL url = null;
		URLConnection urlConn = null;
		InputStreamReader inputStream = null;
		BufferedReader bufferedReader = null;
		ArrayList<String> stockData;
		ArrayList<Stock> alStock = null;
		if (day > 0 && day <= 31 && month >= 0 && month < 12) {
			startMonth = endMonth-1;
			if(endMonth == 0){
				startMonth = 11;
				startYear = endYear-1;
			}
			if(endDay == 31)
				startDay = 30;
			if(startMonth == 1 && startDay > 28) //February
				startDay = 28;
			try {
				url = new URL("http://ichart.yahoo.com/table.csv?s="
						+ symbol + "&d=" + endMonth + "&e=" + endDay + "&f="
						+ endYear + "&g=d&a=" + startMonth + "&b=" + startDay
						+ "&c=" + startYear + "&ignore=.csv");
				urlConn = url.openConnection();
				try {
					alStock = new ArrayList<Stock>();
					inputStream = new InputStreamReader(
							urlConn.getInputStream());
					bufferedReader = new BufferedReader(inputStream);
					bufferedReader.readLine(); /*
												 * first line is not of interest
												 * (only text)
												 */
					while ((csvData = bufferedReader.readLine()) != null) {
						stockData = new ArrayList<String>();
						try {
							StringTokenizer tok = new StringTokenizer(csvData,
									",");
							while (true) {
								try {
									stockData.add(remDoubleQuote(tok
											.nextToken()));
								} catch (NoSuchElementException e) {
									break;
								}
							}
							/*
							 * if there is no data in stockData ArrayList, then
							 * symbol doesnt exist
							 */
							if (stockData.size() != 0)
								alStock.add(createHistoricStockObj(stockData,
										symbol));
						} catch (NullPointerException e) {
							/*
							 * if entered date to catch data was a weekend no
							 * stockdata is available
							 */
						}
					}
				} catch (FileNotFoundException e) {
					/*
					 * if there are no statistics in yahoo financial database
					 * (f.e. if company didnt exist at the stock exchange at the
					 * specified time)
					 */
				}
			} catch (MalformedURLException e) {
				e.printStackTrace();
			} catch (IOException e2) {
				e2.printStackTrace();
			}

			finally {
				try {
					inputStream.close();
					bufferedReader.close();
				} catch (Exception e) {
					// f.e. if inputstream couldn't be created because of
					// missing data from yahoo service
				}
			}
			return alStock;
		} else {
			return alStock;
		}
	}

	private static Stock createHistoricStockObj(ArrayList<String> stockData,
			String symbol) {
		Stock stockObj = new Stock();
		stockObj.setSymbol(symbol);
		stockObj.setDate(stockData.get(0));
		stockObj.setOpen(new BigDecimal(stockData.get(1)));
		stockObj.setHigh(new BigDecimal(stockData.get(2)));
		stockObj.setLow(new BigDecimal(stockData.get(3)));
		stockObj.setLast(new BigDecimal(stockData.get(4)));
		stockObj.setVolume(Integer.parseInt(stockData.get(5)));
		return stockObj;
	}

	/**
	 * Optional method (doesnt get used at the moment) fetches a csv file from
	 * yahoo finance api and creates a Stock object with the data. It is easily
	 * possible to adjust the attributes to get new data about the stocks if necessary.
	 * 
	 * @param symbol
	 *            String with symbol of needed share data
	 * @return Stock object with stock data, Stock Object is null if no data
	 *         could get fetched.
	 */
	public static Stock getYahooData(String symbol) {
		String csvData;
		URL url = null;
		URLConnection urlConn = null;
		InputStreamReader inputStream = null;
		BufferedReader bufferedReader = null;
		ArrayList<String> stockData = new ArrayList<String>();
		Stock stockObj = null;
		try {
			url = new URL("http://quote.yahoo.com/d/quotes.csv?s=" + symbol
					+ "&f=sl1d1t1c1ohgvp2j1pwern&e=.csv");
			urlConn = url.openConnection();
			inputStream = new InputStreamReader(urlConn.getInputStream());
			bufferedReader = new BufferedReader(inputStream);
			csvData = bufferedReader.readLine();
			StringTokenizer tok = new StringTokenizer(csvData, ",");
			while (true) {
				try {
					stockData.add(remDoubleQuote(tok.nextToken()));
				} catch (NoSuchElementException e) {
					break;
				}
			}
			// if last value of share is 0.00 the symbol/share doesn't exist
			if (stockData.get(1).compareTo("0.00") != 0)
				stockObj = createStockObj(stockData);

		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e2) {
			e2.printStackTrace();
		} finally {
			try {
				inputStream.close();
				bufferedReader.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return stockObj;
	}

	/**
	 * Removes double quotes at the beginning or end of a string
	 */
	public static String remDoubleQuote(String tokString) {
		String temp = tokString;
		if (temp.charAt(0) == '"')
			temp = temp.substring(1);
		if (temp.charAt(temp.length() - 1) == '"')
			temp = temp.substring(0, temp.length() - 1);
		return temp;
	}

	public static Stock createStockObj(ArrayList<String> stockData) {
		Stock stockObj = new Stock();
		stockObj.setSymbol(stockData.get(0));
		stockObj.setLast(new BigDecimal(stockData.get(1)));
		stockObj.setDate(stockData.get(2));
		stockObj.setTime(stockData.get(3));
		stockObj.setChange(new BigDecimal(stockData.get(4)));
		stockObj.setOpen(new BigDecimal(stockData.get(5)));
		stockObj.setHigh(new BigDecimal(stockData.get(6)));
		stockObj.setLow(new BigDecimal(stockData.get(7)));
		stockObj.setVolume(Integer.parseInt(stockData.get(8)));
		stockObj.setPercentageChange(stockData.get(9));
		stockObj.setMktCap(stockData.get(10));
		stockObj.setPreviousClose(new BigDecimal(stockData.get(11)));
		stockObj.setAnnRange(stockData.get(12));
		stockObj.setEarns(new BigDecimal(stockData.get(13)));
		stockObj.setPE(stockData.get(14));
		stockObj.setName(stockData.get(15));
		return stockObj;
	}
}